<template>
  <Drawer
    type="confirm"
    use-cancel-event
    :show="visible"
    :title="drawerTitle"
    :confirm-text="drawerConfirmText"
    :confirm-disabled="drawerConfirmDisabled"
    :cancel-text="drawerCancelText"
    :no-cancel="!drawerCancelText"
    @confirm="drawerConfirm"
    @cancel="drawerCancel"
    @close="closeModal"
    @disabled-confirm="drawerDisabledConfirm"
  >
    <template #desc>
      <!-- 程序调整: 无法改善 -->
      <block v-if="feedbackStep === FeedbackSteps.ProposalAdjust && canNotBeImprovedInfo !== null">
        <image class="warning-icon" :src="'/pages/appliance/static/Error.png'" mode="aspectFit" />
        <text>{{ canNotBeImprovedInfo }}</text>
      </block>
      <!-- 程序调整: 完美程序 -->
      <block v-else-if="feedbackStep === FeedbackSteps.ProposalAdjust && isPerfectProposal">
        <text>{{ $t('Appliance.LearningProgram.ProposalAdjust.Modal.Perfect.Content') }}</text>
      </block>
      <!-- 默认描述 -->
      <text v-else>{{ drawerDesc }}</text>
    </template>

    <!-- 评价反馈 -->
    <template v-if="feedbackStep === FeedbackSteps.Feedback">
      <view class="feedback-selection">
        <view v-for="(row, index) in FeedbackRows" :key="index" class="feedback-row">
          <view class="row-header">
            <text>{{ row.title }}</text>
          </view>
          <view class="row-body">
            <view
              v-for="setting in FeedbackSettings"
              :key="setting.value"
              class="feedback-btn"
              :class="{ selected: isFeedbackValueSelected(row.dimension, setting.value) }"
              @click="setFeedbackValue(row.dimension, setting.value)"
            >
              <view class="feedback-icon">
                <image mode="aspectFit" :src="setting.icon" />
              </view>
              <text>{{ setting.label }}</text>
            </view>
          </view>
        </view>
      </view>
    </template>

    <!-- 程序调整 -->
    <template v-if="feedbackStep === FeedbackSteps.ProposalAdjust">
      <ProgramMeta
        auto-load-metadata
        :control="control"
        :scene="LearningViewScene.Feedback"
        :proposal-type="selectedProposal"
        :is-perfect-proposal="isPerfectProposal"
        ref="programMetaRef"
      />
      <view class="proposal-options-view">
        <ProposalOptions v-model:proposal-type="selectedProposal" :options="proposalOptions" :control="control" />
      </view>
    </template>
  </Drawer>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import Drawer from '@/common/drawer.vue'
import { requestSubscribeUsingComplete, showLoading } from '@/utils/mpHelper'
import { getStatusKey, setCommand, setSetting } from '@/api/appliance'
import type { DishwasherController } from '@/controller/Dishwasher/definition'
import {
  LearningDimension,
  FeedbackValue,
  FeedbackCleaningKey,
  FeedbackDryingKey,
  FeedbackDurationKey,
  ProposalCalculationFinished,
  getAcceptProposalKey,
  ProposalType,
} from '@/controller/Dishwasher/Learning/constants'
import netconfig from '@/config/netconfig'
import ProgramMeta from '../components/ProgramMeta.vue'
import ProposalOptions from '../components/ProposalOptions.vue'
import { LearningViewScene, useValidProposalOptions, checkPerfectProposal, useCanNotBeImprovedInfo } from '../constants'
import { trackEvent, TrackType } from '@/dataReport/tracks'
import { safeTrack } from '@/dataReport/dataReportUtil'

const props = defineProps<{
  show: boolean
  control: DishwasherController.Control
}>()
const emit = defineEmits<{
  (e: 'update:show', show: boolean): void
  (e: 'close'): void
  (e: 'confirm'): void
}>()

const i18n = useI18n()
const visible = computed({
  get() {
    return props.show
  },
  set(show) {
    emit('update:show', show)
    !show && emit('close')
  },
})

function closeModal() {
  visible.value = false
}

/**
 * 弹框状态
 */
enum FeedbackSteps {
  Feedback,
  ProposalAdjust,
}
const feedbackStep = ref(FeedbackSteps.Feedback)
watch(
  () => props.show,
  (show) => {
    // 打开时 重置数据
    if (show) {
      feedbackStep.value = FeedbackSteps.Feedback
      feedbackForm.value = getDefaultFeedbackForm()
    }
  }
)

type DrawerConfig = {
  title: string
  desc: string
  confirmText: string
  cancelText?: string
  onConfirm: () => any
}

const drawerConfig: Record<FeedbackSteps, DrawerConfig> = {
  [FeedbackSteps.Feedback]: {
    title: i18n.t('Appliance.LearningProgram.Feedback.Modal.Title'),
    desc: i18n.t('Appliance.LearningProgram.Feedback.Modal.Content'),
    confirmText: i18n.t('APP.Common.Define.Text'),
    cancelText: i18n.t('APP.Common.Cancel.Text'),
    onConfirm: () => submitFeedback(),
  },
  [FeedbackSteps.ProposalAdjust]: {
    title: i18n.t('Appliance.LearningProgram.ProposalAdjust.Modal.Title'),
    desc: i18n.t('Appliance.LearningProgram.ProposalAdjust.Modal.Content'),
    confirmText: i18n.t('APP.Common.Save.Text'),
    cancelText: i18n.t('APP.Common.Cancel.Text'),
    onConfirm: () => confirmProposalAccept(),
  },
}

// 弹框标题
const drawerTitle = computed(() => drawerConfig[feedbackStep.value].title)

// 弹框描述
const drawerDesc = computed(() => drawerConfig[feedbackStep.value].desc)

// 弹框确认文本
const drawerConfirmText = computed(() => drawerConfig[feedbackStep.value].confirmText)
const drawerConfirmDisabled = computed(() => {
  switch (feedbackStep.value) {
    case FeedbackSteps.Feedback: {
      return Object.values(feedbackForm.value).some((val) => val === null)
    }
    case FeedbackSteps.ProposalAdjust: {
      return selectedProposal.value === null
    }
  }
})
// 弹框取消文本
const drawerCancelText = computed(() => drawerConfig[feedbackStep.value].cancelText)
// 弹框确认
function drawerConfirm() {
  drawerConfig[feedbackStep.value].onConfirm()
}
function drawerDisabledConfirm() {
  if (feedbackStep.value === FeedbackSteps.Feedback) {
    uni.showToast({
      title: i18n.t('Appliance.LearningProgram.Feedback.ChooseRequired.Text'),
      icon: 'none',
    })
  }
}
// 弹框取消
function drawerCancel() {
  if (feedbackStep.value === FeedbackSteps.ProposalAdjust) {
    feedbackStep.value = FeedbackSteps.Feedback
    return
  } else {
    closeModal()
  }
}

/**
 * 评价反馈
 */
const FeedbackSettings = [
  {
    label: i18n.t('Appliance.LearningProgram.Feedback.VeryDissatisfied.Text'),
    value: FeedbackValue.VeryDissatisfied,
    icon: '/pages/appliance/static/learning/VeryDissatisfied.png',
  },
  {
    label: i18n.t('Appliance.LearningProgram.Feedback.Dissatisfied.Text'),
    value: FeedbackValue.Dissatisfied,
    icon: '/pages/appliance/static/learning/Dissatisfied.png',
  },
  {
    label: i18n.t('Appliance.LearningProgram.Feedback.Satisfied.Text'),
    value: FeedbackValue.Satisfied,
    icon: '/pages/appliance/static/learning/Satisfied.png',
  },
  {
    label: i18n.t('Appliance.LearningProgram.Feedback.VerySatisfied.Text'),
    value: FeedbackValue.VerySatisfied,
    icon: '/pages/appliance/static/learning/VerySatisfied.png',
  },
]
const FeedbackRows: Array<{
  title: string
  dimension: LearningDimension
}> = [
  {
    title: i18n.t('Appliance.LearningProgram.Meta.Cleaning.Text'),
    dimension: LearningDimension.Cleaning,
  },
  {
    title: i18n.t('Appliance.LearningProgram.Meta.Drying.Text'),
    dimension: LearningDimension.Drying,
  },
  {
    title: i18n.t('Appliance.LearningProgram.Meta.Duration.Text'),
    dimension: LearningDimension.Duration,
  },
]

/**
 * 评价反馈表单
 */
type FeedbackForm = Record<LearningDimension, FeedbackValue | null>
const feedbackForm = ref<FeedbackForm>(getDefaultFeedbackForm())
function getDefaultFeedbackForm(): FeedbackForm {
  return {
    [LearningDimension.Cleaning]: null,
    [LearningDimension.Drying]: null,
    [LearningDimension.Duration]: null,
  }
}
function isFeedbackValueSelected(dimension: LearningDimension, value: FeedbackValue) {
  return feedbackForm.value[dimension] === value
}
function setFeedbackValue(dimension: LearningDimension, value: FeedbackValue) {
  feedbackForm.value[dimension] = value
}

// 提交表单
async function submitFeedback() {
  const formData = feedbackForm.value
  if (Object.values(formData).some((val) => val === null)) {
    return uni.showToast({
      title: i18n.t('Appliance.LearningProgram.Feedback.ChooseRequired.Text'),
      icon: 'none',
    })
  }
  type TrackData = {
    setting_key: unknown
    setting_value: unknown
    successOrNot?: boolean
    error_code?: number
    response_msg?: string
  }
  const trackData: TrackData = {
    setting_key: [],
    setting_value: [],
  }
  trackData.setting_key = Object.keys(formData)
  trackData.setting_value = Object.values(formData)
  try {
    const haId = props.control.store._datasource.haId
    await showLoading(async () => {
      const tasks = [
        setSetting(haId, FeedbackCleaningKey, formData[LearningDimension.Cleaning] as unknown as string, {
          ignoreError: true,
        }),
        setSetting(haId, FeedbackDryingKey, formData[LearningDimension.Drying] as unknown as string, {
          ignoreError: true,
        }),
        setSetting(haId, FeedbackDurationKey, formData[LearningDimension.Duration] as unknown as string, {
          ignoreError: true,
        }),
      ]
      const results = await Promise.all(tasks)
      const errors = results.filter((r) => r.code !== 0)
      if (errors.length !== 0) throw new Error('Submit Error', { cause: errors })

      trackData['successOrNot'] = errors.length == 0
      safeTrack(() => {
        trackEvent('appliance_setting', trackData, TrackType.ApplianceDetail, 'Appliance.Settings.LDW.Setting')
      })
      // 一次性消息订阅
      await requestSubscribeUsingComplete([netconfig.DeviceStateId])

      // 检查是否计算完成 完成后继续执行
      await showLoading(
        () => checkProposalCalculationFinish(),
        i18n.t('Appliance.LearningProgram.Feedback.Calculating.Text')
      )

      // 提示调整成功
      uni.showToast({
        title: i18n.t('Appliance.LearningProgram.Feedback.CalculationFinish.Text'),
        icon: 'success',
      })

      // 打开程序调整弹框
      await toProposalAdjustStep()
    })
  } catch (e) {
    console.error(e)
    uni.showToast({
      title: i18n.t('Appliance.LearningProgram.Feedback.SubmitError.Text'),
      icon: 'none',
    })
  }
}

async function checkProposalCalculationFinish() {
  const haId = props.control.store._datasource.haId

  // 间隔毫秒数
  const interruptTime = 300
  // 总重试次数
  const repeatTime = 5
  // 重试计数
  let repeatCount = 0
  // 是否已计算完成
  let isFinished = false
  try {
    for (let i = repeatCount; i < repeatTime; i++) {
      const res = await getStatusKey(haId, ProposalCalculationFinished)

      isFinished = res.data.value === true
      if (isFinished) break

      // 延迟后重新发起请求
      await new Promise((r) => setTimeout(r, interruptTime))
    }

    if (!isFinished) throw new Error('Calculation timeout')

    return Promise.resolve()
  } catch (e) {
    console.error(e)
    uni.showToast({
      title: i18n.t('Appliance.LearningProgram.Feedback.CalculationFailed.Text'),
      icon: 'none',
    })
    return Promise.reject('Calculation failed')
  }
}

/**
 * 程序调整
 */
// 状态
const allStatus = computed(() => props.control.store._datasource.status)
// Proposal 选项
const proposalOptions = useValidProposalOptions({ allStatus })
const selectedProposal = ref<ProposalType | null>(null)
const isPerfectProposal = computed(() => checkPerfectProposal(proposalOptions.value))
const canNotBeImprovedInfo = useCanNotBeImprovedInfo({ control: props.control, selected: selectedProposal })
// 自动设置默认值
watch(
  () => proposalOptions.value,
  (options) => {
    if (options.length === 0) return

    // 存在完美方案时，选中完美方案
    if (checkPerfectProposal(options)) {
      selectedProposal.value = ProposalType.Current
    }
    // 存在优化方案时，默认选中第一个
    else if (options.length !== 0) {
      selectedProposal.value = options[0].type
    }
  },
  { immediate: true }
)

async function toProposalAdjustStep() {
  await showLoading(async () => {
    // 加载 Status 用于查询 Level
    await props.control.remote.loadAllStatus()
  })
  feedbackStep.value = FeedbackSteps.ProposalAdjust
}

const programMetaRef = ref<InstanceType<typeof ProgramMeta> | null>(null)
// 保存程序调整
async function confirmProposalAccept() {
  if (!selectedProposal.value)
    return uni.showToast({
      title: i18n.t('Appliance.LearningProgram.ProposalAdjust.ChooseRequired.Text'),
      icon: 'none',
    })
  const haId = props.control.store._datasource.haId
  const acceptKey = getAcceptProposalKey(selectedProposal.value)
  safeTrack(() => {
    trackEvent(
      'before_accept_ldw_proposal',
      { proposal_selection: acceptKey, setting_obj: programMetaRef.value?.metaData?.percentage },
      TrackType.ApplianceDetail,
      'Appliance.DishWasher.Proposal.Save'
    )
  })
  let res: any = null
  try {
    res = await showLoading(() => setCommand(haId, acceptKey, true))
  } catch (error) {
    res = error
  } finally {
    safeTrack(() => {
      trackEvent(
        'accept_ldw_proposal',
        {
          proposal_selection: acceptKey,
          setting_obj: programMetaRef.value?.metaData?.percentage,
          successOrNot: res.code == 0,
          error_code: res.code,
          response_msg: res.msg,
        },
        TrackType.ApplianceDetail,
        'Appliance.DishWasher.Proposal.Save'
      )
    })
  }

  // 重置评价反馈状态
  props.control.store.resetFeedbackNoticeReceived()

  uni.showToast({
    title: i18n.t('APP.Common.SaveSucess.Text'),
    icon: 'success',
  })

  closeModal()
}
</script>

<style scoped lang="less">
.warning-icon {
  width: 40rpx;
  height: 40rpx;
  vertical-align: middle;
  margin-right: 6rpx;
}
.feedback-selection {
  .feedback-row + .feedback-row {
    margin-top: 48rpx;
  }
  .row-header {
    font-weight: 500;
    font-size: 32rpx;
    line-height: 40rpx;
    color: var(--dark-color);
    margin-bottom: 16rpx;
  }
  .row-body {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .feedback-btn {
    font-weight: 400;
    font-size: 24rpx;
    line-height: 40rpx;
    text-align: center;
    color: rgba(var(--dark-vector), 0.6);
    &.selected .feedback-icon {
      box-shadow: 0 0 0 4rpx var(--primary-color) inset;
    }
  }
  .feedback-icon {
    width: 128rpx;
    height: 128rpx;
    padding: 24rpx;
    background-color: #f4f4f6;
    margin-bottom: 8rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    > image {
      width: 80rpx;
      height: 80rpx;
    }
  }
}
.proposal-options-view {
  margin-top: 32rpx;
}
</style>
